# Copyright (c) 2022 Presto Labs Pte. Ltd.
# Author: zijin

import json
import traceback
from collections import defaultdict
import datetime

from absl import app, flags

from cc.appcoin2.strategy.basis_strat.support.cache_util import top_volume_symbols
from python.coin_deploy.basis_strat2.strat_list import PROD_STRATS
from xunkemgmt_client.tool.slack_noti import send_to_slack
from cc.appcoin2.strategy.basis_strat_backtest.basis_strat_sim_backtest_util import get_lot_size
from cc.appcoin2.strategy.basis_strat.support.adjust_mmport_universe import get_unsold_coins
from cc.appcoin2.strategy.basis_strat.support.daily_search.slack_helper import SlackHelper
from cc.appcoin2.strategy.basis_strat.support.decomm_coin import execute
from python.coin_deploy.basis_strat2.script.adjust_universe import get_param

FLAGS = flags.FLAGS


def get_symbol(config, base):
  def change_base(sample_symbol):
    prefix = ':'.join(sample_symbol.split(':')[:-1])
    suffix = sample_symbol.split('-')[-1]
    if base == suffix:
      return ''
    symbol = f'{prefix}:{base}-{suffix}'
    return symbol

  sample_symbol = list(config['products'].keys())[0]
  symbol_info = config['products'][sample_symbol]
  if 'symbol' in symbol_info:
    complete_symbol = symbol_info['symbol']
  elif 'trade_symbol' in symbol_info:
    complete_symbol = symbol_info['trade_symbol']
  elif 'product0' in symbol_info:
    complete_symbol = symbol_info['symbol']
  return change_base(complete_symbol)


def get_key_path(driver):
  if 'trade' in driver['feed']:
    mea = driver['feed']['trade']['mea']
    recipe = driver['feed']['trade']['recipe']
  else:
    mea = driver['order'][list(driver['order'])[0]]['mea']
    for _, elem in driver['feed'].items():
      if mea == elem['mea']:
        recipe = elem['recipe']
        break

  if mea.split('.')[1] in driver['order']:
    key = driver['order'][mea.split('.')[1]]['connection_config']['key_filepath']
  else:
    key = driver['order'][list(driver['order'])[0]]['connection_config']['key_filepath']
  return mea, recipe, key


def generate_clear_commands(strat_name, driver, config, base):
  symbol = get_symbol(config, base)
  if not symbol:
    return
  dollar_lot_size = config.get('execution', config).get('dollar_lot_size', 2000)
  lot_size = get_lot_size(symbol, dollar_value=dollar_lot_size)
  mea, recipe, key = get_key_path(driver)
  mear = '.'.join([mea, recipe])

  approach_cmd = [
      '../coin_binary/coin2-bazel-bin-3.10/cc/appcoin2/support/approach_target_position',
      f'--mea {mear}',
      f'--symbol {symbol.split(":")[-1]}',
      f'--key_path {key}',
      f'--target_position 0',
      f'--lot_size {lot_size}',
      f'--pass_bp 0',
      f'--stickiness 5']
  if (mea.startswith('Futures.Huobi') or mea.startswith(
      'Futures.Okex') or mea.startswith('Futures.Bybit')):
    approach_cmd.append('--hard_close')
  if mea.startswith('Futures.Huobi.v1-linear-swap') or mea.startswith('Futures.Okex.v5-swap'):
    approach_cmd.append('--cross_mode')
  approach_cmd = ' '.join(approach_cmd)
  cmd = f'./fab.sh -f basis_strat2/fabfile.py -P clear_position:{strat_name},"{approach_cmd}"'
  return cmd


def clear_unsold(strats_names):
  cmds = []
  strats = []
  for strat_name in strats_names:
    driver_path = f'python/coin_deploy/basis_strat2/driver/{strat_name}.json'
    config_path = f'python/coin_deploy/basis_strat2/config/{strat_name}.json'

    with open(driver_path) as fi:
      driver = json.load(fi)
    with open(config_path) as fi:
      config = json.load(fi)

    mea = get_param('mea', config, strat_name)
    if not mea:
      continue

    market = mea.split('.')[0]
    if FLAGS.market and market != FLAGS.market:
      continue
    try:
      all_existing_bases = []
      for _, elem in config['products'].items():
        if 'trade_symbol' in elem:
          base = elem['trade_symbol'].split(':')[-1].split('-')[0]
        else:
          base = elem['symbol'].split(':')[-1].split('-')[0]
        all_existing_bases.append(base)
      unsold_bases, _ = get_unsold_coins(driver, all_existing_bases)
      left_bases = [base for base in unsold_bases if base not in all_existing_bases]
      if len(left_bases) > 0:
        cmds.extend([generate_clear_commands(strat_name, driver, config, base)
                    for base in left_bases])
        strats.append(strat_name)
        cmds = [cmd for cmd in cmds if cmd]
    except Exception:
      traceback.print_exc()
  with open(FLAGS.cmd_path, 'w') as f:
    f.write('\n'.join(cmds))
    f.close()
  return set(strats), cmds


def main(argv):
  strats = [strat['name'] for strat in PROD_STRATS if FLAGS.strategy_name_contains in strat['name']]
  ownerdict = {strat['name']: strat['owner']
               for strat in PROD_STRATS if FLAGS.strategy_name_contains in strat['name'] and 'owner' in strat}
  strat_names, clear_cmds = clear_unsold(strats)
  if FLAGS.report_slack:
    try:
      mention = set([ownerdict.get(strat, 'yuxuan') for strat in strat_names])
      if len(mention) == 0:
        mention = ['channel']
      if len(clear_cmds) > 0:
        send_to_slack('', FLAGS.slack_channel, 'msg', mention_list=list(mention))
        SlackHelper('.', FLAGS.slack_channel).send_slack_noti(f"Clear unsold cmds {FLAGS.market}", FLAGS.cmd_path, True)
    except BaseException:
      traceback.print_exc()
  if FLAGS.print_only:
    print('\n'.join(clear_cmds))
  else:
    for cmd in clear_cmds:
      execute(cmd, 'python/coin_deploy')


if __name__ == '__main__':
  flags.DEFINE_string('strategy_name_contains', '', '')
  flags.DEFINE_bool('print_only', True, '')
  flags.DEFINE_string('market', 'Futures', '')
  flags.DEFINE_string('cmd_path', 'cmds.sh', '')
  flags.DEFINE_bool('report_slack', True, '')
  flags.DEFINE_string('slack_channel', 'test', '')
  app.run(main)
